/*
 * $Header: /opt/javacvs/bk/src/main/java/com/uusee/framework/dao/hibernate/UniversalDaoHibernate.java,v 1.1 2009/04/02 10:08:51 wangrui Exp $
 * $Revision: 1.1 $
 * $Date: 2009/04/02 10:08:51 $
 * ============================================================================
 *
 * Copyright (c) 2007 Beijing uusee Tech CO.,  All rights reserved.
 *
 * ============================================================================
 */
package com.uusee.framework.dao.hibernate;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.uusee.framework.dao.UniversalDao;
import com.uusee.framework.util.query.CriteriaInfo;
import com.uusee.framework.util.query.CriteriaUtilForHibernate;
import com.uusee.framework.util.query.FilterWrapper;
import com.uusee.framework.util.query.SortWrapper;

/**
 * 数据访问对象(DAO)接口的Hibernate实现。
 * 
 * @author <a href="mailto:wangr.bj@gmail.com">WangRui</a> <a href="mailto:du_yi@bbn.cn">DuYi</a>
 */
public class UniversalDaoHibernate extends HibernateDaoSupport implements UniversalDao {

	/**
	 * 所有Dao子类通用的Log变量。
	 */
	protected final Log log = LogFactory.getLog(getClass());

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#getAll(java.lang.Class)
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> getAll(Class<T> clazz) {
		return (List<T>) getHibernateTemplate().loadAll(clazz);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#get(java.lang.Class, java.io.Serializable)
	 */
	@SuppressWarnings("unchecked")
	public <T> T getById(Class<T> clazz, Serializable id) {
		T o = (T) getHibernateTemplate().get(clazz, id);

		if (o == null) {
			throw new ObjectRetrievalFailureException(clazz, id);
		}

		return o;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#merge(java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	public <T> T merge(T o) {
		T t= (T) getHibernateTemplate().merge(o);
		return t;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#save(java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	public <T> T save(T o) {
		return (T) getHibernateTemplate().save(o);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#update(java.lang.Object)
	 */
	public <T> void update(T o) {
		getHibernateTemplate().update(o);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#delete(java.lang.Class, java.io.Serializable)
	 */
	public <T> void delete(Class<T> clazz, Serializable id) {
		getHibernateTemplate().delete(getById(clazz, id));
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#batchDelete(java.lang.Class, java.io.Serializable[])
	 */
	public <T> void batchDelete(Class<T> clazz, Serializable... id) {
		Session session = getSession(true);
		for (int i = 0; i < id.length; i++) {
			delete(clazz, id[i]);
			if (i % 50 == 0) {
				session.flush();
				session.clear();
			}
		}
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#batchSave(T[])
	 */
	public <T> void batchSave(T... entity) {
		Session session = getSession(true);
		for (int i = 0; i < entity.length; i++) {
			save(entity[i]);
			if (i % 50 == 0) {
				session.flush();
				session.clear();
			}
		}
	}
	
	/**
	 * 批量持久化实体
	 * 
	 * @param <T>
	 * @param entity
	 */
	public <T> void batchSave(Collection<T> entitys) {
		Session session = getSession(true);
		int i = 0;
		for (T o : entitys) {
			save(o);
			if (i % 50 == 0) {
				session.flush();
				session.clear();
			}
			i++;
		}
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#batchUpdate(T[])
	 */
	public <T> void batchUpdate(T... entity) {
		Session session = getSession(true);
		for (int i = 0; i < entity.length; i++) {
			update(entity[i]);
			if (i % 50 == 0) {
				session.flush();
				session.clear();
			}
		}
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#getCount(java.lang.Class)
	 */
	public <T> int getCount(final Class<T> modelClass) {
		Integer count = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(modelClass);
				criteria.setProjection(Projections.rowCount());
				return criteria.uniqueResult();
			}
		});
		return count;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#getEntitiesByCriteriaInfo(java.lang.Class,
	 *      com.uusee.framework.util.query.CriteriaInfo)
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> getEntitiesByCriteriaInfo(final Class<T> modelClass, final CriteriaInfo ci) {
		List<T> entities = (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(modelClass);
				criteria = CriteriaUtilForHibernate.fillCriteria(criteria, ci, false);
				return criteria.list();
			}
		});
		return entities;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.uusee.framework.dao.UniversalDao#getCountByCriteriaInfo(java.lang.Class,
	 *      com.uusee.framework.util.query.CriteriaInfo)
	 */
	public <T> int getCountByCriteriaInfo(final Class<T> modelClass, final CriteriaInfo ci) {
		Integer count = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(modelClass);
				criteria = CriteriaUtilForHibernate.fillCriteria(criteria, ci, true);
				return criteria.uniqueResult();
			}
		});
		if (count == null) {
			count= 0;
		}
		return count;
	}
}